//------------------------------------------------------------------------------
// The contents of this file are subject to the nopCommerce Public License Version 1.0 ("License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at  http://www.nopCommerce.com/License.aspx. 
// 
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. 
// See the License for the specific language governing rights and limitations under the License.
// 
// The Original Code is nopCommerce.
// The Initial Developer of the Original Code is NopSolutions.
// All Rights Reserved.
// 
// Contributor(s): _______. 
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using Tathata.Common.Caching;
using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Data.Common;
using System.Data;
using System.Globalization;
using Tathata.Common.DAL;
using Tathata.Common.BLL.Entities;
using Tathata.Common.BLL.EntityCollections;
using Tathata.Common.DAL.Managers;
using System.Web;
using System.Linq;
using Tathata.Common.Localization;

namespace Tathata.Common.BLL.Managers
{
    /// <summary>
    /// Product manager
    /// </summary>
    public class ProductManager
    {
        #region Constants
        private const string PRODUCTS_BY_ID_KEY = "Nop.product.id-{0}";
        #endregion

        #region Methods
        /// <summary>
        /// Marks a product as deleted
        /// </summary>
        /// <param name="ProductID">Product identifier</param>
        public static void MarkProductAsDeleted(int ProductID)
        {
            Product product = GetByProductID(ProductID);
            if (product != null)
            {
                UpdateProduct(product.ProductID, product.Name, product.ShortDescription,
                    product.FullDescription, product.AdminComment, product.ProductTypeID,
                    product.TemplateID, product.MetaKeywords, product.MetaDescription,
                    product.MetaTitle, product.SEName, product.AllowCustomerReviews, product.RatingSum, product.TotalRatingVotes, product.Published, true, product.CreatedOn, product.UpdatedOn);
             
            }
            if (NopContext.IsCachable)
            {
                bool showHidden = NopContext.Current.IsAdmin;
                NopCache.RemoveByPattern(PRODUCTS_BY_ID_KEY);
            }
        }

        /// <summary>
        /// Gets all products
        /// </summary>
        /// <returns>Product collection</returns>
        public static ProductCollection GetAllProducts()
        {
            bool showHidden = NopContext.Current.IsAdmin;
            return GetAllProducts(showHidden);
        }

        /// <summary>
        /// Gets all products
        /// </summary>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <returns>Product collection</returns>
        public static ProductCollection GetAllProducts(bool showHidden)
        {
            return ProductDBManager.GetAllProducts(showHidden);
        }

        /// <summary>
        /// Gets product
        /// </summary>
        /// <param name="ProductID">Product identifier</param>
        /// <returns>Product</returns>
        public static Product GetByProductID(int ProductID)
        {
            string key = string.Format(PRODUCTS_BY_ID_KEY, ProductID);
            object obj2 = NopCache.Get(key);
            if (NopContext.IsCachable && (obj2 != null))
            {
                return (Product)obj2;
            }

            Product product = ProductDBManager.GetByProductID(ProductID);

            if (NopContext.IsCachable)
            {
                NopCache.Max(key, product);
            }
            return product;
        }

        /// <summary>
        /// Inserts a product
        /// </summary>
        /// <param name="Name">The name</param>
        /// <param name="ShortDescription">The short description</param>
        /// <param name="FullDescription">The full description</param>
        /// <param name="AdminComment">The admin comment</param>
        /// <param name="ProductTypeID">The product type identifier</param>
        /// <param name="TemplateID">The template identifier</param>
        /// <param name="MetaKeywords">The meta keywords</param>
        /// <param name="MetaDescription">The meta description</param>
        /// <param name="MetaTitle">The meta title</param>
        /// <param name="SEName">The search-engine name</param>
        /// <param name="AllowCustomerReviews">A value indicating whether the product allows customer reviews</param>
        /// <param name="RatingSum">The rating sum</param>
        /// <param name="TotalRatingVotes">The total rating votes</param>
        /// <param name="Published">A value indicating whether the entity is published</param>
        /// <param name="Deleted">A value indicating whether the entity has been deleted</param>
        /// <param name="CreatedOn">The date and time of product creation</param>
        /// <param name="UpdatedOn">The date and time of product update</param>
        /// <returns>Product</returns>
        public static Product InsertProduct(string Name, string ShortDescription, string FullDescription, string AdminComment,
            int ProductTypeID, int TemplateID, string MetaKeywords, string MetaDescription, string MetaTitle,
            string SEName, bool AllowCustomerReviews, int RatingSum, int TotalRatingVotes, bool Published, bool Deleted,
            DateTime CreatedOn, DateTime UpdatedOn)
        {
            Product product = ProductDBManager.InsertProduct(Name, ShortDescription, FullDescription, AdminComment,
             ProductTypeID, TemplateID, MetaKeywords, MetaDescription, MetaTitle,
             SEName, AllowCustomerReviews, RatingSum, TotalRatingVotes, Published, Deleted, CreatedOn, UpdatedOn);

            if (NopContext.IsCachable)
            {
                bool showHidden = NopContext.Current.IsAdmin;
                NopCache.RemoveByPattern(PRODUCTS_BY_ID_KEY);
            }
            return product;
        }

        /// <summary>
        /// Updates the product
        /// </summary>
        /// <param name="ProductID">Product identifier</param>
        /// <param name="Name">The name</param>
        /// <param name="ShortDescription">The short description</param>
        /// <param name="FullDescription">The full description</param>
        /// <param name="AdminComment">The admin comment</param>
        /// <param name="ProductTypeID">The product type identifier</param>
        /// <param name="TemplateID">The template identifier</param>
        /// <param name="MetaKeywords">The meta keywords</param>
        /// <param name="MetaDescription">The meta description</param>
        /// <param name="MetaTitle">The meta title</param>
        /// <param name="SEName">The search-engine name</param>
        /// <param name="AllowCustomerReviews">A value indicating whether the product allows customer reviews</param>
        /// <param name="RatingSum">The rating sum</param>
        /// <param name="TotalRatingVotes">The total rating votes</param>
        /// <param name="Published">A value indicating whether the entity is published</param>
        /// <param name="Deleted">A value indicating whether the entity has been deleted</param>
        /// <param name="CreatedOn">The date and time of product creation</param>
        /// <param name="UpdatedOn">The date and time of product update</param>
        /// <returns>Product</returns>
        public static Product UpdateProduct(int ProductID, string Name, string ShortDescription, string FullDescription, string AdminComment,
            int ProductTypeID, int TemplateID, string MetaKeywords, string MetaDescription, string MetaTitle,
            string SEName, bool AllowCustomerReviews, int RatingSum, int TotalRatingVotes, bool Published, bool Deleted, DateTime CreatedOn, DateTime UpdatedOn)
        {
            Product product = ProductDBManager.UpdateProduct(ProductID, Name, ShortDescription, FullDescription, AdminComment,
             ProductTypeID, TemplateID, MetaKeywords, MetaDescription, MetaTitle,
             SEName, AllowCustomerReviews, RatingSum, TotalRatingVotes, Published, Deleted, CreatedOn, UpdatedOn);

            if (NopContext.IsCachable)
            {
                bool showHidden = NopContext.Current.IsAdmin;
                NopCache.RemoveByPattern(PRODUCTS_BY_ID_KEY);
            }

            return product;
        }

        /// <summary>
        /// Sets a product rating
        /// </summary>
        /// <param name="ProductID">Product identifer</param>
        /// <param name="Rating">Rating</param>
        public static void SetProductRating(int ProductID, int Rating)
        {
            if (NopContext.Current.User == null)
                return;

            if (Rating < 1 || Rating > 5)
                Rating = 1;
            ProductDBManager.SetProductRating(ProductID, NopContext.Current.User.CustomerID,
                Rating, DateTime.Now);

            if (NopContext.IsCachable)
            {
                string key = string.Format(PRODUCTS_BY_ID_KEY, ProductID);
                NopCache.Remove(key);
            }
        }

        /// <summary>
        /// Searches products
        /// </summary>
        /// <param name="Keywords">Keywords</param>
        /// <param name="SearchDescriptions">A value indicating whether to search in descriptions</param>
        /// <param name="PageNumber">Page number</param>
        /// <param name="PageSize">Page size</param>
        /// <param name="TotalProducts">Total products found</param>
        /// <returns>Product collection</returns>
        public static ProductCollection Search(string Keywords, bool SearchDescriptions,
           int PageNumber, int PageSize, out int TotalProducts)
        {
            if (String.IsNullOrEmpty(Keywords))
                throw new Exception(LocalizationManager.GetLocaleResourceString("Search.SearchTermCouldNotBeEmpty"));
            if (Keywords.Length < 3)
                throw new Exception(LocalizationManager.GetLocaleResourceString("Search.SearchTermMinimumLengthIs3Characters"));
            if (PageNumber < 1)
                PageNumber = 1;
            if (PageSize < 1)
                PageSize = 20;
            bool showHidden = NopContext.Current.IsAdmin;

            return ProductDBManager.Search(Keywords, SearchDescriptions,
           PageNumber, PageSize, showHidden, out  TotalProducts);
        }

        /// <summary>
        /// Clears a "compare products" list
        /// </summary>
        public static void ClearCompareProducts()
        {
            HttpCookie compareCookie = HttpContext.Current.Request.Cookies.Get("NopCommerce.CompareProducts");
            if (compareCookie != null)
            {
                compareCookie.Values.Clear();
                compareCookie.Expires = DateTime.Now.AddYears(-1);
                HttpContext.Current.Response.Cookies.Set(compareCookie);
            }
        }

        /// <summary>
        /// Gets a "compare products" list
        /// </summary>
        /// <returns></returns>
        public static ProductCollection GetCompareProducts()
        {
            ProductCollection products = new ProductCollection();
            List<int> productIDs = GetCompareProductsIDs();
            foreach (int productID in productIDs)
            {
                Product product = GetByProductID(productID);
                if (product != null)
                    products.Add(product);
            }
            return products;
        }

        /// <summary>
        /// Gets a "compare products" identifier list
        /// </summary>
        /// <returns>"compare products" identifier list</returns>
        public static List<int> GetCompareProductsIDs()
        {
            List<int> productIDs = new List<int>();
            HttpCookie compareCookie = HttpContext.Current.Request.Cookies.Get("NopCommerce.CompareProducts");
            if ((compareCookie == null) || (compareCookie.Values == null))
                return productIDs;
            string[] values = compareCookie.Values.GetValues("CompareProductIDs");
            if (values == null)
                return productIDs;
            foreach (string productId in values)
            {
                int prodId = int.Parse(productId);
                if (!productIDs.Contains(prodId))
                    productIDs.Add(prodId);
            }

            return productIDs;
        }

        /// <summary>
        /// Removes a product from a "compare products" list
        /// </summary>
        /// <param name="ProductID">Product identifer</param>
        public static void RemoveProductFromCompareList(int ProductID)
        {
            List<int> oldProductIDs = GetCompareProductsIDs();
            List<int> newProductIDs = new List<int>();
            newProductIDs.AddRange(oldProductIDs);
            newProductIDs.Remove(ProductID);

            HttpCookie compareCookie = HttpContext.Current.Request.Cookies.Get("NopCommerce.CompareProducts");
            if ((compareCookie == null) || (compareCookie.Values == null))
                return;
            compareCookie.Values.Clear();
            foreach (int newProductID in newProductIDs)
                compareCookie.Values.Add("CompareProductIDs", newProductID.ToString());
            compareCookie.Expires = DateTime.Now.AddDays(1.0);
            HttpContext.Current.Response.Cookies.Set(compareCookie);
        }

        /// <summary>
        /// Adds a product to a "compare products" list
        /// </summary>
        /// <param name="ProductID">Product identifer</param>
        public static void AddProductToCompareList(int ProductID)
        {
            List<int> oldProductIDs = GetCompareProductsIDs();
            List<int> newProductIDs = new List<int>();
            newProductIDs.Add(ProductID);
            foreach (int oldProductID in oldProductIDs)
                if (oldProductID != ProductID)
                    newProductIDs.Add(oldProductID);

            HttpCookie compareCookie = HttpContext.Current.Request.Cookies.Get("NopCommerce.CompareProducts");
            if (compareCookie == null)
                compareCookie = new HttpCookie("NopCommerce.CompareProducts");
            compareCookie.Values.Clear();
            int maxProducts = 5;
            int i = 1;
            foreach (int newProductID in newProductIDs)
            {
                compareCookie.Values.Add("CompareProductIDs", newProductID.ToString());
                if (i == maxProducts)
                    break;
                i++;
            }
            compareCookie.Expires = DateTime.Now.AddDays(1.0);
            HttpContext.Current.Response.Cookies.Set(compareCookie);
        }

        /// <summary>
        /// Gets a "recently viewed products" list
        /// </summary>
        /// <returns>"recently viewed products" list</returns>
        public static ProductCollection GetRecentlyViewedProducts()
        {
            ProductCollection products = new ProductCollection();
            List<int> productIDs = GetRecentlyViewedProductsIDs();
            foreach (int productID in productIDs)
            {
                Product product = GetByProductID(productID);
                if (product != null)
                    products.Add(product);
            }
            return products;
        }

        /// <summary>
        /// Gets a "recently viewed products" identifier list
        /// </summary>
        /// <returns>"recently viewed products" list</returns>
        public static List<int> GetRecentlyViewedProductsIDs()
        {
            List<int> productIDs = new List<int>();
            HttpCookie recentlyViewedCookie = HttpContext.Current.Request.Cookies.Get("NopCommerce.RecentlyViewedProducts");
            if ((recentlyViewedCookie == null) || (recentlyViewedCookie.Values == null))
                return productIDs;
            string[] values = recentlyViewedCookie.Values.GetValues("RecentlyViewedProductIDs");
            if (values == null)
                return productIDs;
            foreach (string productId in values)
            {
                int prodId = int.Parse(productId);
                if (!productIDs.Contains(prodId))
                    productIDs.Add(prodId);
            }

            return productIDs;
        }

        /// <summary>
        /// Adds a product to a "recently viewed products" list
        /// </summary>
        /// <param name="ProductID">Product identifier</param>
        public static void AddProductToRecentlyViewedList(int ProductID)
        {
            List<int> oldProductIDs = GetRecentlyViewedProductsIDs();
            List<int> newProductIDs = new List<int>();
            newProductIDs.Add(ProductID);
            foreach (int oldProductID in oldProductIDs)
                if (oldProductID != ProductID)
                    newProductIDs.Add(oldProductID);

            HttpCookie recentlyViewedCookie = HttpContext.Current.Request.Cookies.Get("NopCommerce.RecentlyViewedProducts");
            if (recentlyViewedCookie == null)
                recentlyViewedCookie = new HttpCookie("NopCommerce.RecentlyViewedProducts");
            recentlyViewedCookie.Values.Clear();
            int maxProducts = SettingManager.GetSettingValueInteger("Display.RecentlyViewedProductCount");
            if (maxProducts <= 0)
                maxProducts = 10;
            int i = 1;
            foreach (int newProductID in newProductIDs)
            {
                recentlyViewedCookie.Values.Add("RecentlyViewedProductIDs", newProductID.ToString());
                if (i == maxProducts)
                    break;
                i++;
            }
            recentlyViewedCookie.Expires = DateTime.Now.AddDays(1.0);
            HttpContext.Current.Response.Cookies.Set(recentlyViewedCookie);
        }

        /// <summary>
        /// Gets a "recently added" product list
        /// </summary>
        /// <param name="Number">Number of products to load</param>
        /// <returns>"recently added" product list</returns>
        public static ProductCollection GetRecentlyAddedProducts(int Number)
        {
            bool showHidden = NopContext.Current.IsAdmin;
            return ProductDBManager.GetRecentlyAddedProducts(Number, showHidden);
        }
        #endregion
    }
}
